(function(angular) {
	'use strict';
	angular.module('fs.waf').

	directive('fsNumFormat', [ '$parse', 'formatService', 'storageService', 'keyDownService', 'SYS_PARAMS', function($parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				linkFunction($scope, $element, $attr, ngModelCtrl, 'number', $parse, formatService, storageService, keyDownService, SYS_PARAMS);
			}
		};
	} ]).

	directive('fsMoneyFormat', [ '$parse', 'formatService', 'storageService', 'keyDownService', 'SYS_PARAMS', function($parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				linkFunction($scope, $element, $attr, ngModelCtrl, 'money', $parse, formatService, storageService, keyDownService, SYS_PARAMS);
			}
		};
	} ]).

	directive('fsPctFormat', [ '$parse', 'formatService', 'storageService', 'keyDownService', 'SYS_PARAMS', function($parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				linkFunction($scope, $element, $attr, ngModelCtrl, 'percentage', $parse, formatService, storageService, keyDownService, SYS_PARAMS);
			}
		};
	} ]).

	directive('fsSstFormat', [ '$filter', '$parse', 'formatService', 'storageService', 'keyDownService', 'SYS_PARAMS', function($filter, $parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				linkFunction($scope, $element, $attr, ngModelCtrl, 'sensitive', $parse, formatService, storageService, keyDownService, SYS_PARAMS);
			}
		};
	} ]).

	directive('fsDateFormat', [ '$parse', 'formatService', 'storageService', 'keyDownService', 'SYS_PARAMS', function($parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				linkFunction($scope, $element, $attr, ngModelCtrl, 'date', $parse, formatService, storageService, keyDownService, SYS_PARAMS);
			}
		};
	} ]).

	directive('fsUppercase', [ '$filter', function($filter) {
		return {
			restrict : 'A',
			require : 'ngModel',
			link : function($scope, $element, $attr, ngModelCtrl) {
				if ($scope.$eval($attr.fsUppercase) === true || $filter('uppercase')($attr.fsUppercase) == 'TRUE') {
					ngModelCtrl.$parsers.push(function(input) {
						var capitalized = angular.isString(input) ? $filter('uppercase')(input) : input;
						if (capitalized !== input) {
							// see where the cursor is before the update so that we can set it back
							var selection = getCursortPosition($element[0]);
							ngModelCtrl.$setViewValue(capitalized);
							ngModelCtrl.$render();
							// set back the cursor after rendering
							$element[0].selectionStart = selection;
							$element[0].selectionEnd = selection;
						}
						return capitalized;
					});
				}
			}
		};
	} ]);

	function linkFunction($scope, $element, $attr, ngModelCtrl, formatType, $parse, formatService, storageService, keyDownService, SYS_PARAMS) {
		var pattern, getter, setter, value, watcher, watchers = [], needFormat = true;
		var isEmpty = function (value) {
			return (value === null || angular.isUndefined(value) || (angular.isString(value) ? value.trim() == '' : false));
		};
		var getPattern = function(formatType) {
			var _pattern, fsFormat;
			if (formatType == 'number') {
				fsFormat = $attr.fsNumFormat;
			} else if (formatType == 'money') {
				fsFormat = $attr.fsMoneyFormat;
			} else if (formatType == 'percentage') {
				fsFormat = $attr.fsPctFormat;
			} else if (formatType == 'date') {
				fsFormat = $attr.fsDateFormat;
			} else if (formatType == 'sensitive') {
				fsFormat = $attr.fsSstFormat;
			}
			if (fsFormat && (formatType == 'number' || formatType == 'money' || formatType == 'percentage') && fsFormat.match('[#0]')) {
				_pattern = fsFormat;
			} else if(formatType == 'date' && fsFormat.indexOf('yyyy') != -1){
				_pattern = fsFormat;
			} else {
				// for numberFormat the _pattern may be 'vm.ratingType.scoreDecimal' or '#0.0' or 'defaultInteger' etc.
				// for moneyFormat the pattern may be 'USD' or 'vm.product.loanAmtRangeCcy' or 'loanAmtRangeCcy' or 'moeny0' etc
				if (!fsFormat) {
					return null;
				}
				_pattern = $parse(fsFormat)($scope.fsGridConfig ? $scope.fsGridConfig.appScope : $scope);
				if (isEmpty(_pattern))
					_pattern = $parse(fsFormat)($scope.ngModel);
				//for sensitive
				if (isEmpty(_pattern))
					_pattern = $parse(fsFormat)($scope);
			}
			return _pattern || fsFormat;

		};
		$scope.$on('$destroy', function() {
			while (watchers.length) {
				watchers.shift()();
			}
		});
		
		getter = $parse($attr.ngModel);
		setter = getter.assign;
		
		watcher = $scope.$watch($attr.ngModel, function(value, oldValue) {
			if (needFormat && !isEmpty(value)) {
				if (angular.isNumber(value) && value == 0) {
					if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
						ngModelCtrl.$viewValue = '';
						$element.val('');
						return;
					}
				}
				if (formatType == 'number') {
					pattern = getPattern(formatType);
					value = formatService.formatNumber(value, pattern);
					setter($scope, formatService.parseNumber(value));
					$element.val(value);
				} else if (formatType == 'money') {
					pattern = getPattern(formatType);
					value = formatService.formatMoney(value, pattern);
					setter($scope, formatService.parseMoney(value));
					$element.val(value);
				} else if (formatType == 'percentage') {
					pattern = getPattern(formatType);
					value = formatService.formatPercentage(value, pattern);
					setter($scope, formatService.parsePercentage(value));
					$element.val(value);
				} else if (formatType == 'date') {
					pattern = getPattern(formatType);
					value = formatService.formatDate(value, pattern);
					$element.val(value);
				} else if (formatType == 'sensitive') {
					pattern = getPattern(formatType);
					value = formatService.formatSst(value, pattern);
					$element.val(value);
				}
			}
		}, true);
		watchers.push(watcher);
		try {
			if (formatType == 'number') {//--for format like 'vm.feeCode.feeCcy'
				watcher = $scope.fsGridConfig.appScope.$watch($attr.fsNumFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatNumber(value, pattern);
							setter($scope, formatService.parseNumber(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
				watcher = $scope.$watch('ngModel.' + $attr.fsNumFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatNumber(value, pattern);
							setter($scope, formatService.parseNumber(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
			} else if (formatType == 'money') {
				watcher = $scope.fsGridConfig.appScope.$watch($attr.fsMoneyFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatMoney(value, pattern);
							setter($scope, formatService.parseMoney(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
				watcher = $scope.$watch('ngModel.' + $attr.fsMoneyFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatMoney(value, pattern);
							setter($scope, formatService.parseMoney(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
			} else if (formatType == 'sensitive') {
				watcher = $scope.$watch($attr.fsSstFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (!isEmpty(value)) {
							value = formatService.formatSst(value, pattern);
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
			} else if (formatType == 'percentage') {
				watcher = $scope.fsGridConfig.appScope.$watch($attr.fsPctFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatPercentage(value, pattern);
							setter($scope, formatService.parsePercentage(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
				watcher = $scope.$watch('ngModel.' + $attr.fsPctFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
							if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
								$element.val('');
								return;
							}
						}
						if (!isEmpty(value)) {
							value = formatService.formatPercentage(value, pattern);
							setter($scope, formatService.parsePercentage(value));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
			} else if (formatType == 'date') {
				watcher = $scope.fsGridConfig.appScope.$watch($attr.fsDateFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (!isEmpty(value)) {
							value = formatService.formatDate(value, pattern);
							setter($scope, formatService.parseDate(value, pattern));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
				watcher = $scope.$watch('ngModel.' + $attr.fsDateFormat, function(pattern) {
					if (needFormat && !isEmpty(pattern)) {
						value = getter($scope);
						if (!isEmpty(value)) {
							value = formatService.formatDate(value, pattern);
							setter($scope, formatService.parseDate(value, pattern));
							$element.val(value);
						}
					}
				});
				watchers.push(watcher);
			}
		} catch (e) {
		}

		$element.bind('focus', function(e) {
			needFormat = false;
			if (formatType != 'date') {
				if (angular.isNumber(getter($scope)) && getter($scope) == 0 && ngModelCtrl.$viewValue == '') {
					if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
						return;
					}
				}
				// see where the cursor is before the update so that we can set it back
				var selection = getCursortPosition($element[0]);
				$element.val(getter($scope));
				// set back the cursor after rendering
				$element[0].selectionStart = selection;
				$element[0].selectionEnd = selection;
			}
		});

		$element.bind('blur', function(e) {
			needFormat = true;
			value = getter($scope);
			if (formatType == 'number' && !isEmpty(value)) {
				if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
					if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
						return;
					}
				}
				pattern = getPattern(formatType);
				value = formatService.formatNumber(value, pattern);
				if (!isEmpty(value)) {
					setter($scope, formatService.parseNumber(value));
					$element.val(value);
				} else {
					setter($scope, '');
					$element.val('');
				}
			} else if (formatType == 'money' && !isEmpty(value)) {
				if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
					if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
						return;
					}
				}
				pattern = getPattern(formatType);
				value = formatService.formatMoney(value, pattern);
				if (!isEmpty(value)) {
					setter($scope, formatService.parseMoney(value));
					$element.val(value);
				} else {
					setter($scope, '');
					$element.val('');
				}
			} else if (formatType == 'sensitive' && !isEmpty(value)) {
				pattern = getPattern(formatType);
				value = formatService.formatSst(value, pattern);
				if (!isEmpty(value)) {
					$element.val(value);
				} else {
					$element.val('');
				}
			} else if (formatType == 'percentage' && !isEmpty(value)) {
				if (angular.isNumber(value) && value == 0 && ngModelCtrl.$viewValue == '') {
					if ($scope.fsGridConfig.filter && $scope.fsGridConfig.filter == 'zeroEmpty') {
						return;
					}
				}
				pattern = getPattern(formatType);
				value = formatService.formatPercentage(value, pattern);
				if (!isEmpty(value)) {
					setter($scope, formatService.parsePercentage(value));
					$element.val(value);
				} else {
					setter($scope, '');
					$element.val('');
				}
			}
		});
		/*if (formatType != 'date' && formatType != 'sensitive' && formatType != 'number') {
			$element.bind('keydown', function(e) {
				function stopEvent(e) {
					if(e.preventDefault){
			            e.preventDefault();
			        }else{
			            e.returnValue = false;
			        }
				}
				var theEvent = window.event || e;
				var code = theEvent.keyCode || theEvent.which;
				if (getter($scope) && ('' + getter($scope)).indexOf('.') >= 0 && (code == 110 || code == 190)) {
					stopEvent(theEvent);
				}
				if (((code != 8 && code != 37 && code != 39 && code < 48) || (code > 57 && code < 96) || code > 105) && code != 110 && (code != 190 || theEvent.shiftKey == true) && !(code == 86 && theEvent.ctrlKey == true)) {
					stopEvent(theEvent);
				}
			});
		}*/
		if (formatType == 'number' || formatType == 'money' || formatType == 'percentage') {
			$element.bind('keydown', function(e) {
				function stopEvent(e) {
					if(e.preventDefault){
			            e.preventDefault();
			        }else{
			            e.returnValue = false;
			        }
				}
				var theEvent = window.event || e;
				var position = getCursortPosition($element[0]);
				var value =  $element.val(), isValidKey = true;
				var formatInfo = storageService.getFormatInfo() || {};
				if($scope.fsGridConfig && $scope.fsGridConfig.options && $scope.fsGridConfig.options.allowNegative) {
					if(keyDownService.minusKeyDown(e) && (isEmpty(value) || value.indexOf("-") == -1)) return;
					if(position == 0 && value.indexOf("-") != -1) {
						stopEvent(theEvent);
						return;
					}
					if(keyDownService.minusKeyDown(e) && position > 0) {
						stopEvent(theEvent);
						return;
					}
				}
				
				pattern = getPattern(formatType);
				if (formatType == 'money') {
					var ccyConfig = SYS_PARAMS.CCY_CONFIG, zeros = ".000000000000000000000000000000000000000000000000", fractionDigits;
					formatInfo = storageService.getFormatInfo() || {};
					if (ccyConfig[angular.uppercase(pattern)]) {
						fractionDigits = ccyConfig[angular.uppercase(pattern)];
						pattern = (formatInfo.money0 || '#,##0') + zeros.substr(0, fractionDigits + 1);
					} else {
						pattern = formatInfo[pattern];
						pattern = pattern || formatInfo['defaultMoney'];
					}
				} else if (formatType == 'percentage') {
					pattern = formatInfo[pattern];
					pattern = pattern || defaultFormat.percentage;
				} else if (formatType == 'number') {
					pattern = formatInfo[pattern];
					pattern = pattern || formatInfo.defaultFloat;
				}
				if (pattern.indexOf('.') >= 0) {
					isValidKey = keyDownService.floatKeyDown(e, value);
				} else {
					isValidKey = keyDownService.numKeyDown(e, value);
				}
					
			    if(!isValidKey) {
			    	stopEvent(theEvent);
			    }
			});
		}
	}
	
	function getCursortPosition(textDom) {
		var cursorPos = 0;
		if (document.selection) {
			// IE Support
			textDom.focus();
			var selectRange = document.selection.createRange();
			selectRange.moveStart('character', -textDom.value.length);
			cursorPos = selectRange.text.length;
		} else if (textDom.selectionStart || textDom.selectionStart == '0') {
			// Firefox support
			cursorPos = textDom.selectionStart;
		}
		return cursorPos;
	}
})(angular);